package token

import (
	"context"
	"errors"
	"lion-passport/internal/dao/model"
	data "lion-passport/internal/redis"
	"log"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/go-redis/redis/v8"
)

const (
	SECRETKEY         = "42wqTE23123wffLU94342wgldgFs"
	MAXAGE            = 3600 * 24
	REFRESH_MAXAGE    = 3600 * 24 * 7
	CACHE_BLACK_TOKEN = "black.token."
)

type CustomClaims struct {
	UserId uint
	Type   string
	jwt.StandardClaims
}

// 产生token
func (cc *CustomClaims) MakeToken() (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, cc)
	return token.SignedString([]byte(SECRETKEY))
}

func GenerateToken(account model.Account) (string, string, error) {
	customClaims := &CustomClaims{
		UserId: uint(account.ID),
		Type:   account.Type,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Duration(MAXAGE) * time.Second).Unix(), // 过期时间，必须设置
		},
	}
	accessToken, err := customClaims.MakeToken()
	if err != nil {
		return "", "", err
	}
	refreshClaims := &CustomClaims{
		UserId: uint(account.ID),
		Type:   account.Type,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Duration(REFRESH_MAXAGE) * time.Second).Unix(), // 过期时间，必须设置
		},
	}
	refreshToken, err := refreshClaims.MakeToken()
	if err != nil {
		return "", "", err
	}

	return accessToken, refreshToken, nil
}

func ParseToken(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, jwt.NewValidationError("unexpected signing method", jwt.ValidationErrorSignatureInvalid)
		}
		return []byte(SECRETKEY), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, jwt.NewValidationError("invalid token", jwt.ValidationErrorMalformed)
}

func ParseRefreshToken(refreshToken string) (newAccessToken, newRefreshToken string, err error) {
	refreshClaims, err := ParseToken(refreshToken)

	if err != nil {
		return
	}

	if refreshClaims.ExpiresAt > time.Now().Unix() {
		// Token is still valid, generate new access token
		return GenerateToken(model.Account{
			ID:   int32(refreshClaims.UserId),
			Type: refreshClaims.Type,
		})
	}

	return "", "", errors.New("身份过期，重新登录")
}


func GetUserIdByAccessToken(accessToken string) (string, error) {
	ctx := context.Background()
	userId, err := data.Rdb.Get(ctx, "access:"+accessToken).Result()
	if err != nil {
		if err == redis.Nil {
			log.Printf("Access token not found in Redis: %s\n", accessToken)
			return "", nil // Token not found
		}
		log.Printf("Error getting user ID by access token: %v\n", err)
		return "", err // Other error
	}
	return userId, nil
}
